﻿using System.ServiceModel;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Web.Script.Serialization;

namespace Home.ZWave
{
    [ServiceContract(Name = "HomeService")]
    public class HomeService
    {
        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public string getInterface()
        {
            var home = GetRecursiveCategory(System.Guid.Empty);

            return new JavaScriptSerializer().Serialize(home);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public string getCategories(System.Guid categoryGuid)
        {
            var query = from c in HomeManager.Instance.GetHomeContext().Categories where (categoryGuid == System.Guid.Empty && c.ParentCategoryGuid == null) || (categoryGuid != System.Guid.Empty && c.ParentCategoryGuid == categoryGuid) select c;

            ArrayList a = new ArrayList(query.Count());

            foreach (Category c in query)
            {
                a.Add(new { CategoryGuid = c.CategoryGuid, Label = c.Label });
            }

            return new JavaScriptSerializer().Serialize(a);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool setScene(System.Guid sceneGuid)
        {
            var query = from v in HomeManager.Instance.GetHomeContext().SceneValues where sceneGuid == v.SceneGuid select v;

            ArrayList a = new ArrayList(query.Count());

            bool returnValue = true;

            foreach (SceneValue sv in query)
            {
                if (!HomeManager.Instance.SetValue(sv.ZWValue, sv.Value)) returnValue = false;
            }

            return returnValue;
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public string getWidgets(System.Guid categoryGuid)
        {
            var query = from w in HomeManager.Instance.GetHomeContext().Widgets where w.Category.CategoryGuid == categoryGuid select w;

            ArrayList a = new ArrayList(query.Count());

            foreach (Widget w in query)
            {
                w.ValueReference.Load();
                w.CategoryReference.Load();
                a.Add(new { CategoryGuid = w.Category.CategoryGuid, Label = w.Label, WidgetGuid = w.WidgetGuid, WidgetTypeId = w.WidgetTypeId, CurrentValue = w.Value.CurrentValue, SortOrder = w.SortOrder });
            }

            return new JavaScriptSerializer().Serialize(a);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public string getValues()
        {
            var query = from v in HomeManager.Instance.GetHomeContext().Values where v.GenreId == 1 orderby v.NodeId select v;

            ArrayList a = new ArrayList(query.Count());

            foreach (Value v in query)
            {
                v.DeviceReference.Load();
                a.Add(new { ValueGuid = v.ValueGuid, Label = v.Label, DeviceLabel = v.Device.Label, NodeId = v.NodeId });
            }

            return new JavaScriptSerializer().Serialize(a);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool addCategory(System.Guid parentGuid, string categoryName, string sortOrder, bool isWidgetGroup)
        {
            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();
            int sortOrderInt = 0;
            int.TryParse(sortOrder, out sortOrderInt);

            Category cat = new Category();
            cat.CategoryGuid = System.Guid.NewGuid();
            cat.Label = categoryName;
            cat.Name = categoryName;
            cat.IsWidgetGroup = isWidgetGroup;
            cat.SortOrder = sortOrderInt;

            if (parentGuid != System.Guid.Empty)
            {
                cat.ParentCategoryGuid = parentGuid;
            }

            homeContext.AddToCategories(cat);
            homeContext.SaveChanges();

            return true;
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool addWidget(System.Guid parentGuid, string widgetName, int sortOrder, int widgetTypeId, System.Guid valueGuid)
        {
            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();

            Widget w = new Widget();
            w.WidgetGuid = System.Guid.NewGuid();
            w.Category = homeContext.Categories.FirstOrDefault(c => c.CategoryGuid == parentGuid);
            w.Label = widgetName;
            w.SortOrder = sortOrder;
            w.WidgetTypeId = widgetTypeId;
            w.Value = homeContext.Values.FirstOrDefault(v => v.ValueGuid == valueGuid);

            int maximum = 99;

            int.TryParse(w.Value.Maximum, out maximum);

            if (widgetTypeId == 2)
            {
                w.RequireValueTranslation = true;

                for (int i = 0; i <= 10; i++)
                {
                    WidgetValue wv = new WidgetValue();
                    wv.WidgetGuid = w.WidgetGuid;
                    wv.SortOrder = (short)i;
                    wv.ValueVal = (((double)i / 10.0) * maximum).ToString();
                    wv.WidgetVal = (i * 10).ToString() + " %";

                    w.ValueTranslations.Add(wv);
                }
            }

            homeContext.AddToWidgets(w);
            homeContext.SaveChanges();

            return true;
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool changeCategoryName(System.Guid categoryGuid, string categoryName)
        {
            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();

            var category = homeContext.Categories.FirstOrDefault(
                c => c.CategoryGuid == categoryGuid);

            if (category == null) return false;

            category.Label = categoryName;

            homeContext.SaveChanges();

            return true;
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool changeWidgetName(System.Guid widgetGuid, string widgetName)
        {
            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();

            var widget = homeContext.Widgets.FirstOrDefault(
                w => w.WidgetGuid == widgetGuid);

            if (widget == null) return false;

            widget.Label = widgetName;

            homeContext.SaveChanges();

            return true;
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool deleteCategory(System.Guid categoryGuid)
        {
            List<System.Guid> categoryHierarchy = new List<System.Guid>();

            getCategoryHierarchy(categoryGuid, categoryHierarchy);

            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();

            foreach (System.Guid catGuid in categoryHierarchy)
            {
                var category = homeContext.Categories.FirstOrDefault(c => c.CategoryGuid == catGuid);

                homeContext.DeleteObject(category);
            }

            foreach (Widget w in homeContext.Widgets)
            {
                w.CategoryReference.Load();
                if (w.Category == null) homeContext.DeleteObject(w);
            }

            homeContext.SaveChanges();

            return true;
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool deleteWidget(System.Guid widgetGuid)
        {
            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();

            var widget = homeContext.Widgets.FirstOrDefault(
                w => w.WidgetGuid == widgetGuid);

            if (widget == null) return false;

            homeContext.DeleteObject(widget);

            var widgetValues = from wv in homeContext.WidgetValues
                               where wv.WidgetGuid == widgetGuid
                               select wv;

            foreach (WidgetValue wv in widgetValues)
            {
                homeContext.DeleteObject(wv);
            }

            homeContext.SaveChanges();

            return true;
        }

        private void getCategoryHierarchy(System.Guid parentCategoryGuid, List<System.Guid> categoryHierarchy)
        {
            categoryHierarchy.Add(parentCategoryGuid);

            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();

            var subCategories = from c in homeContext.Categories
                                where
                                    c.ParentCategoryGuid.Value == parentCategoryGuid
                                select c;

            foreach (Category c in subCategories)
            {
                getCategoryHierarchy(c.CategoryGuid, categoryHierarchy);
            }
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public string getComPort()
        {
            return HomeManager.Instance.GetSettingValue(HomeManager.comPortSettingKey);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public string getServerAddress()
        {
            return HomeManager.Instance.GetSettingValue(HomeManager.baseAddressSettingKey);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool setComPort(string value)
        {
            return HomeManager.Instance.SetSettingValue(HomeManager.comPortSettingKey, value);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool setServerAddress(string value)
        {
            return HomeManager.Instance.SetSettingValue(HomeManager.baseAddressSettingKey, value);
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public bool changeValue(System.Guid widgetGuid, string newValue)
        {
            var widget = HomeManager.Instance.GetHomeContext().Widgets.FirstOrDefault(
                w => w.WidgetGuid == widgetGuid);

            if (widget == null) return false;

            widget.ValueReference.Load();

            if (widget.RequireValueTranslation)
            {
                newValue = HomeManager.Instance.GetTranslatedValueValue(widget.WidgetGuid, newValue);
            }

            try
            {
                return HomeManager.Instance.SetValue(widget.Value, newValue);
            }
            catch
            {
                return false;
            }
        }

        [OperationContract]
        [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
        public string getNotifications(System.Guid clientGuid)
        {
            object[] notifications = HomeManager.Instance.GetNotifications(clientGuid);

            return new JavaScriptSerializer().Serialize(notifications);
        }

        private object GetRecursiveCategory(System.Guid categoryGuid)
        {
            HomeConnection homeContext = HomeManager.Instance.GetHomeContext();

            var categoryInfo = homeContext.Categories.FirstOrDefault(c => c.CategoryGuid == categoryGuid);

            if (categoryInfo == null)
            {
                categoryInfo = new Category();
                categoryInfo.CategoryGuid = System.Guid.Empty;
                categoryInfo.Label = string.Empty;
                categoryInfo.IsWidgetGroup = false;
                categoryInfo.Name = string.Empty;
                categoryInfo.SortOrder = 0;
            }

            var parent = new { CategoryGuid = categoryInfo.CategoryGuid, Label = categoryInfo.Label, IsWidgetGroup = categoryInfo.IsWidgetGroup, SortOrder = categoryInfo.SortOrder, Children = new ArrayList(), Widgets = new ArrayList() };

            var subCategories = from c in homeContext.Categories
                                where (categoryGuid == System.Guid.Empty && c.ParentCategoryGuid == null) ||
                                        (categoryGuid != System.Guid.Empty && c.ParentCategoryGuid == categoryGuid)
                                orderby c.SortOrder
                                select c;

            var widgets = from w in homeContext.Widgets
                          where (categoryGuid == System.Guid.Empty && w.Category.CategoryGuid == null) ||
                                 (categoryGuid != System.Guid.Empty && w.Category.CategoryGuid == categoryGuid)
                          orderby w.SortOrder
                          select w;

            foreach (Category c in subCategories)
            {
                parent.Children.Add(GetRecursiveCategory(c.CategoryGuid));
            }

            foreach (Widget w in widgets)
            {
                w.ValueReference.Load();
                w.CategoryReference.Load();
                ArrayList valueTranslations = null;

                string realVal = w.Value.CurrentValue;

                if (w.RequireValueTranslation)
                {
                    realVal = HomeManager.Instance.GetTranslatedWidgetValue(w.WidgetGuid, realVal);

                    valueTranslations = new ArrayList();

                    w.ValueTranslations.Load();

                    var widgetValueQuery =
                        from wn in homeContext.WidgetValues
                        where wn.WidgetGuid == w.WidgetGuid
                        orderby wn.SortOrder
                        select wn;

                    foreach (WidgetValue wv in widgetValueQuery)
                    {
                        valueTranslations.Add(new { Value = wv.WidgetVal });
                    }
                }

                parent.Widgets.Add(new { WidgetGuid = w.WidgetGuid, Label = w.Label, WidgetTypeId = w.WidgetTypeId, CurrentValue = realVal, Values = valueTranslations });
            }

            return parent;
        }
    }
}

